/*
 * image_body_visualizer.c
 * This file is part of gURL
 *
 * Copyright (C) 2014 - Aleksey Konovalov
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Library General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "image_body_visualizer.h"

#include "body_visualizer.h"
#include <glib/gi18n.h>

struct _ImageBodyVisualizer {
    GtkScrolledWindow parent;
    GtkWidget* image;
};

struct _ImageBodyVisualizerClass {
    GtkScrolledWindowClass parent;
};

static void image_body_visualizer_interface_init(BodyVisualizerInterface* iface);

G_DEFINE_TYPE_WITH_CODE(ImageBodyVisualizer, image_body_visualizer, GTK_TYPE_SCROLLED_WINDOW,
                        G_IMPLEMENT_INTERFACE(BODY_VISUALIZER_TYPE,
                                              image_body_visualizer_interface_init))

static void image_body_visualizer_change_session(BodyVisualizer* self,
                                                Session* session) {
    ImageBodyVisualizer* ibv = IMAGE_BODY_VISUALIZER(self);
    gboolean ok = FALSE;
    if(session) {
        const GString* body = session_get_response_body(session);
        GInputStream* stream = g_memory_input_stream_new_from_data(
                                 body->str, body->len, NULL);
        GdkPixbuf* pb = gdk_pixbuf_new_from_stream(stream, NULL, NULL);
        g_object_unref(stream);
        if(pb) {
            gtk_image_set_from_pixbuf(GTK_IMAGE(ibv->image), pb);
            ok = TRUE;
        }
    }
    if(!ok)
        gtk_image_clear(GTK_IMAGE(ibv->image));
}

static void info_cb (GdkPixbufLoader *loader, 
                     int              width,
                     int              height,
                     gpointer         data)
{
    GdkPixbufFormat **format = data;
    *format = gdk_pixbuf_loader_get_format (loader);
    gdk_pixbuf_loader_set_size (loader, 0, 0);
}

static gboolean image_body_visualizer_check_is_compatible(BodyVisualizer* self,
                                                          Session* session) {
    const size_t BLOCK_SIZE = 1024;
    if(!session)
        return FALSE;
    ImageBodyVisualizer* ibv = IMAGE_BODY_VISUALIZER(self);
    const GString* body = session_get_response_body(session);

    GdkPixbufFormat* format = NULL;
    GdkPixbufLoader* loader = gdk_pixbuf_loader_new();
    g_signal_connect(loader, "size-prepared", G_CALLBACK(info_cb), &format);

    for(const char* ptr = body->str, *endptr = body->str + body->len;
        !format && ptr < endptr; ptr += BLOCK_SIZE) {
        if(!gdk_pixbuf_loader_write(loader, (const guchar*)ptr,
                                    MIN(BLOCK_SIZE, endptr - ptr), NULL))
            break;
    }

    gboolean result = format != NULL;

    gdk_pixbuf_loader_close(loader, NULL);
    g_object_unref(loader);

    return result;
}

static void image_body_visualizer_interface_init(BodyVisualizerInterface* iface) {
    iface->change_session = image_body_visualizer_change_session;
    iface->check_is_compatible = image_body_visualizer_check_is_compatible;
    iface->name = _("Image");
}

static void image_body_visualizer_init(ImageBodyVisualizer* self) {
    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(self), GTK_SHADOW_IN);
    gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(self), NULL);
    gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(self), NULL);
    g_object_set(G_OBJECT(self), "margin", 7, NULL);

    self->image = gtk_image_new();
    gtk_widget_show(self->image);
    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(self), self->image);
}

static void image_body_visualizer_class_init(ImageBodyVisualizerClass* klass) {}

GtkWidget* image_body_visualizer_new() {
    return g_object_new(IMAGE_BODY_VISUALIZER_TYPE, NULL);
}
